package com.klikmee.sms.core.base.communicator.mtel;

import hr.tis.mgw.client.GatewayException;
import hr.tis.mgw.client.message.DeliveryReport;
import hr.tis.mgw.client.message.MessageId;
import hr.tis.mgw.client.message.MessageManager2;
import hr.tis.mgw.client.message.ReceivedSms;
import hr.tis.mgw.client.message.SmsMessage;
import hr.tis.mgw.client.message.Status;
import hr.tis.mgw.client.message.notification.MessageListener2;

import java.util.Date;
import java.util.List;

import org.apache.log4j.Logger;

import com.klikmee.sms.core.base.Core;
import com.klikmee.sms.core.base.communicator.SendSmsIntercepter;
import com.klikmee.sms.core.base.util.Constants;
import com.klikmee.sms.core.base.util.DeliveryReports;
import com.klikmee.sms.core.model.BulkMessage;
import com.klikmee.sms.core.model.IncomingMessage;
import com.klikmee.sms.core.model.OutgoingMessage;
import com.klikmee.sms.core.model.Provider;

/**
 * This Class represents communicator for Mtel provider
 */
public class MTelCommunicatorImpl implements MTelCommunicator {

	/**
	 * Ref to the {@link Logger} object used to log events and messages
	 */
	private Logger			logger			= Logger.getLogger( MTelCommunicatorImpl.class );
	/**
	 * Reference to the {@link Core} object responsible global message management
	 */
	private Core			core			= null;

	/**
	 * Instance of the mtel provider
	 */
	private Provider		mtelProvider	= null;

	/**
	 * Reference to the {@link MessageManager2} object responsible for communication with mGw mtel system.
	 */
	private MessageManager2	messageManager	= null;

	/**
	 * Concrete message listener used to receive message notifications
	 */
	private MessageListener2 messageListener = null;
	
	/**
	 * Default constructor for {@link MTelCommunicatorImpl} class.
	 */
	public MTelCommunicatorImpl() {

	}

	/**
	 * Init method used to initialize communicator's resources and properties.
	 * Registers message listener at message manager implementation.
	 */
	public void init() {
		// register message listener for 
		messageManager.registerMessageListener( MessageManager2.REG_ID_ANY, messageListener );
	}

	/**
	 * Sends sms message. Parameters are extracted from {@link OutgoingMessage} object. This method then calls
	 * {@link MessageManager2#sendMessage(hr.tis.mgw.client.message.Message, String[], String, hr.tis.mgw.client.message.Priority, hr.tis.mgw.client.charging.Charging)} method which encapsulates
	 * communication with Mtel provider. Mtel returns MessageId param which can be used to retreive delivery status for the message.
	 * 
	 * @param outgoingMessage
	 *            Outgoing message to send
	 */
	@Override
	public void sendMessage( OutgoingMessage outgoingMessage ) {

		// prepare message parmeters
		String messageText = outgoingMessage.getMessage();
		String[] destinations = new String[] { outgoingMessage.getToNumber() };
		String orignirator = outgoingMessage.getFromNumber();

		// prepare message object
		SmsMessage smsMessage = new SmsMessage( messageText );

		try {
			MessageId messageId = this.messageManager.sendMessage( smsMessage, destinations, orignirator, null, null );
			outgoingMessage.setProvidersMesssageId( messageId.getId() );

			// notify core about message sent event
			this.core.onMessageSent( outgoingMessage );
		} catch (GatewayException e) {
			//TODO: implement exception handling

		}

	}

	/**
	 * Invoked on new sms messages received over Mtel operater. Message attributes are extracted and passed over to Core in form of {@link IncomingMessage} object
	 * 
	 * @param receivedSms
	 *            mtel sms message representation
	 */
	@Override
	public void onSmsMessage( ReceivedSms receivedSms ) {
		// this is core representation of the new message
		IncomingMessage message = new IncomingMessage();

		// set message attributes
		message.setFromNumber( receivedSms.getSenderAddress() );
		message.setMessage( receivedSms.getSmsMessage().getText() );
		message.setOurIncomingTime( new Date() );
		message.setProvider( this.mtelProvider );
		message.setToNumber( receivedSms.getDestinationAddress() );
		message.setTypeOfMessage( Constants.MESSAGE_TYPE_SMS );
		
		core.enqueueIncomingMessage( message );
		
		logger.info( String.format( "Sms message from %s forwarded to core.", receivedSms.getSenderAddress()));
		
	}

	/**
	 * Invoked on new delivery reports received over MTel communicator. Delivery report attributes are extracted and passed to Core in form of {@link OutgoingMessage} object.
	 * 
	 * @param deliveryReport
	 *            mtel delivery report representation
	 */
	@Override
	public void onDeliveryReport( DeliveryReport deliveryReport ) {
		
		// holder for the status resport
		OutgoingMessage outgoingMessage = new OutgoingMessage();
		
		// resolve status
		int status = resolveStatus(deliveryReport.getStatus());
		
		// get providers message id
		String messageId = deliveryReport.getMessageId();

		// setup message params
		outgoingMessage.setProvidersMesssageId( messageId );
		outgoingMessage.setDeliveryStatus( status );
		outgoingMessage.setProvider( this.mtelProvider );
		
		core.enqueueStatusReport( outgoingMessage );
		
		logger.info( String.format( "Received delivery report for messageId = [%s], status = [%s]", deliveryReport.getMessageId(), deliveryReport.getStatus().getValue() ) );
	}
	
	@Override
	public List<SendSmsIntercepter> getSendSmsIntercepters() {
		// TODO Auto-generated method stub
		return null;
	}

	/**
	 * Resolves mtel status report to core's native status report.
	 * @param status mtel status obj to be resolved
	 * @return native status report value
	 */
	private int resolveStatus( Status status ) {
		if(status.equals( Status.DELIVERED )){
			return DeliveryReports.DELIVERED;
		}
		else if(status.equals( Status.DELIVERY_IMPOSSIBLE )){
			return DeliveryReports.MTel.DELIVERY_IMPOSSIBLE;
		}
		
		else if(status.equals( Status.DELIVERY_UNCERTAIN )){
			return DeliveryReports.MTel.DELIVERY_UNCERTAIN;
		}
		
		else if(status.equals( Status.MESSAGE_WAITING )){
			return DeliveryReports.MTel.MESSAGE_WAITING;
		}
		
		else return -1;
	}

	@Override
	public void sendBulkMessage( BulkMessage bulkMessage ) {
		// TODO Auto-generated method stub

	}

	public void setMessageManager( MessageManager2 messageManager ) {
		this.messageManager = messageManager;
	}

	public void setCore( Core core ) {
		this.core = core;
	}
	
	public void setMessageListener( MessageListener2 messageListener ) {
		this.messageListener = messageListener;
	}


}
